/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package compiler.parser.lalr;

import compiler.grammar.NonTerminal;
import compiler.grammar.Terminal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

/**
 *
 * @author meemo
 */
public class LALRUtils
{
    //~ Methods ----------------------------------------------------------------

    public static ArrayList<GotoData> getGotosOf(LALRState state)
    {
        ArrayList<GotoData> data = new ArrayList<GotoData>();

        for (LALRTransition trans : state.getTransitions())
        {
            if (trans.getTransitionOn() instanceof NonTerminal)
            {
                GotoData gd = new GotoData();
                gd.stateID       = trans.getTransitionTo().getId();
                gd.nonTerminalId = trans.getTransitionOn().getId();

                data.add(gd);
            }
        }

        return data;
    }

    public static ArrayList<ReduceData> getReductionsOf(LALRState state)
    {
        ArrayList<ReduceData> data = new ArrayList<ReduceData>();

        for (LALRItem itm : state.getItems())
        {
            if (itm.isDotAtEnd())
            {
                ReduceData rd = new ReduceData();
                rd.productionId = itm.getProduction().getId();

                // only add lookahead if it is not default action
                boolean defaultAction = state.getItems().size() == 1;

                if (!defaultAction)
                    rd.lookahead = itm.getLookAhead();
                else
                    rd.lookahead = new HashSet<Terminal>();

                data.add(rd);
            }
        }

        // every item might have a reduction
        // we need the lookahead of the reduction to decide which one to reduce with
        // if the lookahead is not unique, it's a reduce-reduce error.
        // we will not need to look at the lookahead only if there is one reduction
        if (data.size() == 1)
        {
            /*
             * this case can happend in that grammar
             *  <Z> = <A> ;
             *  <A> = [a]<B>[b]
             *  | [a][d][c]
             *  | [b]<B>[c]
             *  | [b][d][d];
             *  <B> = [d];
             */
            data.get(0).lookahead = new HashSet<Terminal>();
        }

        return data;
    }

    public static ArrayList<ShiftData> getShiftsOf(LALRState state)
    {
        ArrayList<ShiftData> data = new ArrayList<ShiftData>();

        for (LALRTransition trans : state.getTransitions())
        {
            if (trans.getTransitionOn() instanceof Terminal)
            {
                ShiftData sd = new ShiftData();
                sd.stateID    = trans.getTransitionTo().getId();
                sd.terminalId = trans.getTransitionOn().getId();

                data.add(sd);
            }
        }

        return data;
    }

    //~ Inner Interfaces -------------------------------------------------------

    public static interface Action {}

    //~ Inner Classes ----------------------------------------------------------

    public static class GotoData
    {
        public int nonTerminalId;
        public int stateID;
    }

    public static class Reduce implements Action
    {
        public int productionId;

        public Reduce(int productionNumber)
        {
            this.productionId = productionNumber;
        }
    }

    public static class ReduceData
    {
        public Set<Terminal> lookahead = null;
        public int           productionId;
    }

    public static class Shift implements Action
    {
        public int stateNumber;

        public Shift(int stateNumber)
        {
            this.stateNumber = stateNumber;
        }
    }

    public static class ShiftData
    {
        public int stateID;
        public int terminalId;
    }
}
